<template>
  <div>
    <!-- 返回的意思 -->
    <van-nav-bar @click-left="$router.back()" left-arrow title="编辑资料" />
    <!-- 头像修改区域 -->
    <div class="avatar-box">
      <!-- after-read钩子 -->
      <!-- 它绑定的函数会在选择完文件后调用 -->
      <van-uploader :after-read="afterRead" />
      <van-image round fit="cover" :src="userInfo.photo" />
    </div>
    <!-- 三个cell区域：显示名字、性别、生日 -->
    <van-cell-group>
      <van-cell @click="doEditName" title="名称" :value="userInfo.name" />
      <van-cell
        @click="popShow = true"
        title="性别"
        :value="userInfo.gender ? '男' : '女'"
      />
      <van-cell @click="showBirthday" title="生日" :value="userInfo.birthday" />
    </van-cell-group>

    <!-- 弹出框 - 用来修改名字 -->
    <!-- v-model绑定的数据是用来控制弹出框的显示和隐藏 -->
    <van-dialog
      @confirm="updateName"
      v-model="nameShow"
      title="修改名字"
      show-cancel-button
    >
      <van-field ref="nameInp" class="name-field" v-model="editName" />
    </van-dialog>

    <!-- 弹出层 - 用来修改性别 -->
    <!-- v-model绑定的数据用来控制显示和隐藏 -->
    <van-popup class="genderPop" v-model="popShow" position="bottom">
      <van-nav-bar
        @click-left="popShow = false"
        title="修改性别"
        left-text="取消"
      />
      <van-cell @click="changeGender(1)" title="男" is-link />
      <van-cell @click="changeGender(0)" title="女" is-link />
    </van-popup>

    <!-- 弹出层 - 修改生日的 -->
    <van-popup v-model="birthShow" position="bottom" class="birthPop">
      <!-- v-model：用来获取和设置当前时间 -->
      <!-- min-date：用来设置最小能选择的日期 -->
      <!-- max-date：用来设置最大能选择的日期 -->
      <van-datetime-picker
        @cancel="birthShow = false"
        @confirm="editBirth"
        v-model="currentDate"
        type="date"
        title="选择年月日"
        :min-date="minDate"
        :max-date="maxDate"
      />
    </van-popup>

    <!-- 图片裁剪容器 -->
    <div class="crop-box" v-if="cropShow">
      <!-- 
        ref： 方便后面通过$refs找到它 
        img： 设置要被裁剪的图片
        autoCrop：代表产生一个裁剪框
        autoCropWidth和autoCropHeight设置裁剪框宽高
      -->
      <vueCropper
        ref="cropper"
        :img="cropImg"
        autoCrop
        autoCropWidth="180"
        autoCropHeight="180"
      ></vueCropper>

      <van-button @click="doCrop" type="primary">裁剪</van-button>
      <van-button @click="cropShow = false" type="primary">取消</van-button>
    </div>
  </div>
</template>

<script>
import { editUserInfoAPI, changeUserPhotoAPI } from "@/api";
// 导入moment
import moment from "moment";

// 导入裁剪插件
import { VueCropper } from "vue-cropper";

export default {
  components: {
    VueCropper,
  },
  data() {
    return {
      nameShow: false,
      editName: "",
      popShow: false,
      birthShow: false,
      // 最小选择日期
      minDate: new Date(1949, 9, 1),
      // 最大选择日期
      maxDate: new Date(),
      // 设置默认时间 - 这个无所谓反正到时候都要用代码改
      currentDate: new Date(2021, 0, 17),
      cropShow: false,
      cropImg: "",
    };
  },
  methods: {
    doEditName() {
      // 显示出弹出框(这里仅仅只是改了数据，渲染是异步的，要等这里的同步执行完才去渲染)
      this.nameShow = true;
      // 把名字显示给输入框
      this.editName = this.userInfo.name;
      // 并且让输入框获得焦点，所以给输入框加ref找到输入框
      // console.log(this.$refs.nameInp)
      // this.$refs.nameInp.focus()
      // 函数会在下一次dom更新时调用
      // 提示：$nextTick也可以用await，彻底杜绝回调函数，大家自己可以试
      this.$nextTick(() => {
        this.$refs.nameInp.focus();
      });
    },

    // 点击修改名字的弹出框里的确认按钮触发
    async updateName() {
      // 非空判断
      if (this.editName == "") return this.$toast("请输入名字");
      // 调用接口发请求修改资料
      await editUserInfoAPI({ name: this.editName });
      // 此时是修改完了，但是要刷新才能看到效果
      // 为了不刷新，我们就应该把修改后的结果自己改动到vuex里
      this.$store.commit("changeUserInfo", {
        // 我把之前的属性还都得保留下来
        ...this.userInfo,
        name: this.editName,
      });
    },

    // 修改性别的点击事件
    async changeGender(gender) {
      // 点击后要发请求修改
      await editUserInfoAPI({ gender });

      // 修改成功要改到vuex里
      this.$store.commit("changeUserInfo", {
        // 我把之前的属性还都得保留下来
        ...this.userInfo,
        gender,
      });

      // 让弹出层隐藏
      this.popShow = false;
    },

    // 点击生日cell的事件
    showBirthday() {
      // 显示出生日
      this.birthShow = true;
      // 把用户的生日赋值给日期选择器的当前日期
      // 注意：vuex里保存的数据是字符串，但是这里要给的是日期对象
      // 所以要转换
      this.currentDate = new Date(this.userInfo.birthday);
    },

    // 点击日期里的确认事件
    async editBirth() {
      // 发请求修改生日
      // 接口要求传递的是字符串，所以你不能直接传currentDate，因为它是日期对象
      // 所以现在我们要把日期对象，改成字符串形式 - "YYYY-MM-DD"
      const birthday = moment(this.currentDate).format("YYYY-MM-DD");
      await editUserInfoAPI({ birthday });

      // 改动到vuex
      this.$store.commit("changeUserInfo", {
        ...this.userInfo,
        birthday,
      });

      // 隐藏弹出层
      this.birthShow = false;
    },

    // 当选择完文件后会调用的钩子
    // 这个钩子默认有个参数
    afterRead(data) {
      // 把选择图片的base64给裁剪绑定的img
      this.cropImg = data.content;
      // 把裁剪容器显示出来
      this.cropShow = true;
    },

    // 裁剪的点击事件
    doCrop() {

      this.$refs.cropper.getCropBlob(async (data) => {
        // 这里的参数data就是裁剪后的文件对象
        // 拿到裁剪后的对象是为了上传给服务器
        // 所以这里要发请求
        // ajax不能直接上传文件，要上传文件必须要用到 FormData 这个对象（ajax2.0）
        // 如果jQuery要用 FormData 上传，都还得加两句话contentType:false processData:false

        // axios本质上发的就是ajax请求，所以肯定也得要FormData
        let fm = new FormData()
        fm.append('photo', data)
        // 直接把FormData作为对象参数传递进去即可
        let res = await changeUserPhotoAPI( fm )
        // console.log(res) // res.data.data.photo 就是服务器返回的图片上传后的地址

        // 发完请求要更新vuex里的头像
        this.$store.commit('changeUserInfo', {
          ...this.userInfo,
          photo: res.data.data.photo
        })

        // 把裁剪区域隐藏了
        this.cropShow = false
      });
    },
  },
  async created() {
    //  调用vuex里的方法获取数据
    this.$store.dispatch("getUserInfo");
  },

  computed: {
    userInfo() {
      return this.$store.state.userInfo;
    },
  },
};
</script>

<style lang="less" scoped>
// 加了scoped，这里写的样式
// 只能给这里写过的标签用，没写的标签用不上

// 头像盒子
.avatar-box {
  @width: 120px;
  height: @width;
  display: flex;
  justify-content: center;
  align-items: center;

  .van-image {
    width: 100px;
    height: 100px;
  }

  .van-uploader {
    // 因为只有当绝对定位或者固定定位才不占位置
    // 就能显示图片
    position: absolute;
    z-index: 999;

    ::v-deep .van-uploader__upload {
      width: 100vw;
      height: @width;
      opacity: 0;
    }
  }
}

.name-field {
  border: 1px solid #ddd;
}
.genderPop {
  height: 130px;
}

.birthPop {
  height: 220px;
}

.crop-box {
  width: 100vw;
  height: 100vh;
  position: fixed;
  left: 0;
  top: 0;

  .van-button {
    position: absolute;
    bottom: 0;

    // 找到最后一个button
    &:last-of-type {
      right: 0;
    }
  }
}
</style>